//
// Created by 夏申频 on 17/1/26.
//

#include "LibJpegCodec.h"
#include <sstream>
#include "libjpegSupport/JPEGPlus.h"
#include "ImageCodec.h"
#include <stdio.h>

void setImageMeta(ImageMeta* meta,JPEG::Decoder* decoder){
    meta->width = decoder->image_width();
    meta->height = decoder->image_height();
    meta->channels = decoder->num_components();
    meta->colorSpace = decoder->out_color_space();
    meta->bitsPerSample = decoder->data_precision();
}

int jpegDecode(int bit,ImageCodecContext* c,ImageCodecErr* err){

//    printf("c:%08x\n",c);
//    printf("size:%d\n",SIZEOF(ImageCodecContext));
    //printf("c.input:%08x\n",c->input);
   // printf("c.inputSize:%d\n",c->inputSize);
//    printf("c.output:%08x\n",c->output);
//    printf("c.outputSize:%08x\n",c->outputSize);
//    printf("c.meta:%08x\n",c->meta);



    std::string sin(c->input,c->inputSize);
    std::ostringstream out;
    std::istringstream in(sin);
    JPEG::STDImageInputStream *iis  = new   JPEG::STDImageInputStream(in);
    JPEG::STDImageOutputStream* ios = new JPEG::STDImageOutputStream(out);

    JPEG::LongJumpErrorHandler* errorHandler = new JPEG::LongJumpErrorHandler;


    JPEG::Decoder* decoder = JPEG::jpegDecoder(bit);
    decoder->setErrorHandler(errorHandler);
    if(setjmp(errorHandler->setjmp_buffer)){
        std::cout<<decoder->lastErrorMsg()<<std::endl;
        err->code = decoder->lastErrorCode();
        std::string msg(decoder->lastErrorMsg());
        strncpy(err->msg,msg.data(),msg.size());
        return err->code;
    }

    decoder->setInput(iis);
    decoder->readHeader(true);

    setImageMeta(c->meta,decoder);

    decoder->start();

    int readLine = 0;
    do{
        readLine = decoder->readScanLines(1,ios);
    }while (readLine>0);

    decoder->finish();

    std::string pic (out.str());

    int outputSize = pic.size();

    char* buffer = (char*)malloc(outputSize);

    if (buffer != nullptr){
        memcpy(buffer,pic.data(),outputSize);
        *(c->outputSize) = outputSize;
        *(c->output) = buffer;
    }

    delete iis;
    delete ios;
    delete errorHandler;
    delete decoder;

    return err->code;

}
int jpegEncode(int bit,ImageCodecContext* c,ImageCodecErr* err){

    std::string sin(c->input,c->inputSize);
    std::ostringstream out;
    std::istringstream in(sin);
    JPEG::STDImageInputStream* iis  = new   JPEG::STDImageInputStream(in);
    JPEG::STDImageOutputStream* ios = new JPEG::STDImageOutputStream(out);

    JPEG::LongJumpErrorHandler* errorHandler = new JPEG::LongJumpErrorHandler;

    JPEG::Encoder* e = JPEG::jpegEncoder(bit);

    e->setErrorHandler(errorHandler);
    if(setjmp(errorHandler->setjmp_buffer)){
        std::cout<<e->lastErrorMsg()<<std::endl;
        err->code = e->lastErrorCode();
        std::string msg(e->lastErrorMsg());
        strncpy(err->msg,msg.data(),msg.size());
        return err->code;
    }

    e->setOutput(ios);

    e->image_width(c->meta->width);
    e->image_height(c->meta->height);
    e->in_color_space((J_COLOR_SPACE)c->meta->colorSpace);
    e->input_components(c->meta->channels);

    e->setDefault();
    //e->data_precision(16);
    //e->jpeg_color_space(JCS_GRAYSCALE);
    // e->num_components(1);


    if (c->extra[LOSSLESS] == TRUE){
        e->lossy(FALSE);
    } else{
        e->quality(c->extra[QUALITY]);
    }

    e->start();

    int writeLine = 0;
    do{
        writeLine = e->writeScanLines(1,iis);
    }while (writeLine>0);

    e->finish();

    std::string pic (out.str());

    int outputSize = pic.size();

    char* buffer = (char*)malloc(outputSize);

    if (buffer != nullptr){
        memcpy(buffer,pic.data(),outputSize);
        *(c->outputSize) = outputSize;
        *(c->output) = buffer;
    }

    delete iis;
    delete ios;
    delete errorHandler;
    delete e;

    return err->code;
}